{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Creating a polygon from a list of points\n",
    "\n",
    "For many of those working with geo data it is a common task being asked to create a polygon from a list of points. More specific, to create a polygon that wraps around those points in a meaningful manner. So, there are several sources in the web explaining how to create the shape (see sources at end of document). This example notebook is the application of those solutions to folium maps."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helpers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports\n",
    "import random\n",
    "\n",
    "import folium\n",
    "from scipy.spatial import ConvexHull\n",
    "\n",
    "\n",
    "# Function to create a list of some random points\n",
    "def randome_points(amount, LON_min, LON_max, LAT_min, LAT_max):\n",
    "\n",
    "    points = []\n",
    "    for _ in range(amount):\n",
    "        points.append(\n",
    "            (random.uniform(LON_min, LON_max), random.uniform(LAT_min, LAT_max))\n",
    "        )\n",
    "\n",
    "    return points\n",
    "\n",
    "\n",
    "# Function to draw points in the map\n",
    "def draw_points(map_object, list_of_points, layer_name, line_color, fill_color, text):\n",
    "\n",
    "    fg = folium.FeatureGroup(name=layer_name)\n",
    "\n",
    "    for point in list_of_points:\n",
    "        fg.add_child(\n",
    "            folium.CircleMarker(\n",
    "                point,\n",
    "                radius=1,\n",
    "                color=line_color,\n",
    "                fill_color=fill_color,\n",
    "                popup=(folium.Popup(text)),\n",
    "            )\n",
    "        )\n",
    "\n",
    "    map_object.add_child(fg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Convex hull\n",
    "\n",
    "The convex hull is probably the most common approach - its goal is to create the smallest polygon that contains all points from a given list. The scipy.spatial package provides this algorithm (https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.spatial.ConvexHull.html, accessed 29.12.2018)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function that takes a map and a list of points (LON,LAT tupels) and\n",
    "# returns a map with the convex hull polygon from the points as a new layer\n",
    "\n",
    "\n",
    "def create_convexhull_polygon(\n",
    "    map_object, list_of_points, layer_name, line_color, fill_color, weight, text\n",
    "):\n",
    "\n",
    "    # Since it is pointless to draw a convex hull polygon around less than 3 points check len of input\n",
    "    if len(list_of_points) < 3:\n",
    "        return\n",
    "\n",
    "    # Create the convex hull using scipy.spatial\n",
    "    form = [list_of_points[i] for i in ConvexHull(list_of_points).vertices]\n",
    "\n",
    "    # Create feature group, add the polygon and add the feature group to the map\n",
    "    fg = folium.FeatureGroup(name=layer_name)\n",
    "    fg.add_child(\n",
    "        folium.vector_layers.Polygon(\n",
    "            locations=form,\n",
    "            color=line_color,\n",
    "            fill_color=fill_color,\n",
    "            weight=weight,\n",
    "            popup=(folium.Popup(text)),\n",
    "        )\n",
    "    )\n",
    "    map_object.add_child(fg)\n",
    "\n",
    "    return map_object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe src=\"about:blank\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" data-html=PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgCiAgICAgICAgPHNjcmlwdD4KICAgICAgICAgICAgTF9OT19UT1VDSCA9IGZhbHNlOwogICAgICAgICAgICBMX0RJU0FCTEVfM0QgPSBmYWxzZTsKICAgICAgICA8L3NjcmlwdD4KICAgIAogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NvZGUuanF1ZXJ5LmNvbS9qcXVlcnktMS4xMi40Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUubWluLmNzcyIvPgogICAgCiAgICAgICAgICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsCiAgICAgICAgICAgICAgICBpbml0aWFsLXNjYWxlPTEuMCwgbWF4aW11bS1zY2FsZT0xLjAsIHVzZXItc2NhbGFibGU9bm8iIC8+CiAgICAgICAgICAgIDxzdHlsZT4KICAgICAgICAgICAgICAgICNtYXBfNmQzOTQ5ZGU3Y2QxNDUxNmEzODhjM2ExZTNhNDIzMjAgewogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGhlaWdodDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGxlZnQ6IDAuMCU7CiAgICAgICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwXzZkMzk0OWRlN2NkMTQ1MTZhMzg4YzNhMWUzYTQyMzIwIiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKICAgICAgICAgICAgdmFyIG1hcF82ZDM5NDlkZTdjZDE0NTE2YTM4OGMzYTFlM2E0MjMyMCA9IEwubWFwKAogICAgICAgICAgICAgICAgIm1hcF82ZDM5NDlkZTdjZDE0NTE2YTM4OGMzYTFlM2E0MjMyMCIsCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgY2VudGVyOiBbNDguNSwgOS41XSwKICAgICAgICAgICAgICAgICAgICBjcnM6IEwuQ1JTLkVQU0czODU3LAogICAgICAgICAgICAgICAgICAgIHpvb206IDgsCiAgICAgICAgICAgICAgICAgICAgem9vbUNvbnRyb2w6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgcHJlZmVyQ2FudmFzOiBmYWxzZSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIAoKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl9hNTE1ZmZjMTI2NTc0MDViOGE1OGIxNTZlZjFiMDhjYSA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgImh0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nIiwKICAgICAgICAgICAgICAgIHsiYXR0cmlidXRpb24iOiAiRGF0YSBieSBcdTAwMjZjb3B5OyBcdTAwM2NhIGhyZWY9XCJodHRwOi8vb3BlbnN0cmVldG1hcC5vcmdcIlx1MDAzZU9wZW5TdHJlZXRNYXBcdTAwM2MvYVx1MDAzZSwgdW5kZXIgXHUwMDNjYSBocmVmPVwiaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIlx1MDAzZU9EYkxcdTAwM2MvYVx1MDAzZS4iLCAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsICJtYXhOYXRpdmVab29tIjogMTgsICJtYXhab29tIjogMTgsICJtaW5ab29tIjogMCwgIm5vV3JhcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEsICJzdWJkb21haW5zIjogImFiYyIsICJ0bXMiOiBmYWxzZX0KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNmQzOTQ5ZGU3Y2QxNDUxNmEzODhjM2ExZTNhNDIzMjApOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwX2VhNTE3ODQ5ZGY2YTQ5ZDI4OTg4OGUxMjNmMTRkMmM3ID0gTC5mZWF0dXJlR3JvdXAoCiAgICAgICAgICAgICAgICB7fQogICAgICAgICAgICApLmFkZFRvKG1hcF82ZDM5NDlkZTdjZDE0NTE2YTM4OGMzYTFlM2E0MjMyMCk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvbHlnb25fOTViODg0YmQ5YTFlNGNiZThhOTI4ZDBkYmRjODk4MmUgPSBMLnBvbHlnb24oCiAgICAgICAgICAgICAgICBbWzQ4LjEyNjkzMzg1NDUzNjgzLCA5LjQ4MzkwNjA4NTExNTc2Nl0sIFs0OC4wMTc5NTg1MzM1MTM0NywgOS4yNDIxMzg5NTcyNDg0NTRdLCBbNDguNzA5OTA3NjA4ODc1OTcsIDkuMTA2MzM1NjAwMDk0MTQ1XSwgWzQ4Ljc4NjU4MzcyNDIwODcsIDkuMTI3OTM4MTE0ODUzNzI1XSwgWzQ4LjY3OTM4ODQyOTUzNzA1NiwgOS4yOTQyNjgxMjQyMjkzMzNdLCBbNDguNDAxODU3MTIwMTg3MzUsIDkuNjAwMTgxMjIzNDAwOTQzXV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAibGlnaHRibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImxpZ2h0c2t5Ymx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJub0NsaXAiOiBmYWxzZSwgIm9wYWNpdHkiOiAxLjAsICJzbW9vdGhGYWN0b3IiOiAxLjAsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogNX0KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwX2VhNTE3ODQ5ZGY2YTQ5ZDI4OTg4OGUxMjNmMTRkMmM3KTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8zYzE4MGYzOWUxOGQ0ZTNhYmQxOTA3YjAxODhjN2Q2OSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfM2U1MjhhNjgwZmU2NDUxYzhlOThlMzU3YTllYmE3MzcgPSAkKGA8ZGl2IGlkPSJodG1sXzNlNTI4YTY4MGZlNjQ1MWM4ZTk4ZTM1N2E5ZWJhNzM3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzNjMTgwZjM5ZTE4ZDRlM2FiZDE5MDdiMDE4OGM3ZDY5LnNldENvbnRlbnQoaHRtbF8zZTUyOGE2ODBmZTY0NTFjOGU5OGUzNTdhOWViYTczNyk7CiAgICAgICAgCgogICAgICAgIHBvbHlnb25fOTViODg0YmQ5YTFlNGNiZThhOTI4ZDBkYmRjODk4MmUuYmluZFBvcHVwKHBvcHVwXzNjMTgwZjM5ZTE4ZDRlM2FiZDE5MDdiMDE4OGM3ZDY5KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgZmVhdHVyZV9ncm91cF81NDJhZGVkZjBiNWM0MDAyYjQ5YjU1NmYyOWE5YmNiYyA9IEwuZmVhdHVyZUdyb3VwKAogICAgICAgICAgICAgICAge30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNmQzOTQ5ZGU3Y2QxNDUxNmEzODhjM2ExZTNhNDIzMjApOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2ViMTExMDI4ZWEzYTRmNzM5MDM1YTZmYjVmMGI1YjY2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguNzA5OTA3NjA4ODc1OTcsIDkuMTA2MzM1NjAwMDk0MTQ1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF81NDJhZGVkZjBiNWM0MDAyYjQ5YjU1NmYyOWE5YmNiYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZTUxMmYwZTAwMDI1NDNlYjg2MTk4MDAzZTlmOTgwNDEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzhkYjkzZDBiNmY2YjRlNmNhZjJhZWZhOTI5M2I5ZDAyID0gJChgPGRpdiBpZD0iaHRtbF84ZGI5M2QwYjZmNmI0ZTZjYWYyYWVmYTkyOTNiOWQwMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZTUxMmYwZTAwMDI1NDNlYjg2MTk4MDAzZTlmOTgwNDEuc2V0Q29udGVudChodG1sXzhkYjkzZDBiNmY2YjRlNmNhZjJhZWZhOTI5M2I5ZDAyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9lYjExMTAyOGVhM2E0ZjczOTAzNWE2ZmI1ZjBiNWI2Ni5iaW5kUG9wdXAocG9wdXBfZTUxMmYwZTAwMDI1NDNlYjg2MTk4MDAzZTlmOTgwNDEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2I2ZjZiOTk2ZDVmNjQwODI5ZTA4MTU3ODg5NzhhZGE1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguMjM2MTgxOTU0MjEyNzk2LCA5LjQ0MDA1NjQ5NzIxNDgwOF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAicm95YWxibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogInJveWFsYmx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfNTQyYWRlZGYwYjVjNDAwMmI0OWI1NTZmMjlhOWJjYmMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2U1YjY1ZmQ2ZDRkMTQ4ODI5NTEwN2NlMDE1ZWZhMDcyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMzNkOTg3NzViMDc0ZjY3OGFiMWI4N2Y1ZDUwNjEzMSA9ICQoYDxkaXYgaWQ9Imh0bWxfZjMzZDk4Nzc1YjA3NGY2NzhhYjFiODdmNWQ1MDYxMzEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2U1YjY1ZmQ2ZDRkMTQ4ODI5NTEwN2NlMDE1ZWZhMDcyLnNldENvbnRlbnQoaHRtbF9mMzNkOTg3NzViMDc0ZjY3OGFiMWI4N2Y1ZDUwNjEzMSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYjZmNmI5OTZkNWY2NDA4MjllMDgxNTc4ODk3OGFkYTUuYmluZFBvcHVwKHBvcHVwX2U1YjY1ZmQ2ZDRkMTQ4ODI5NTEwN2NlMDE1ZWZhMDcyKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hYWVmM2U2YzQ4Yjk0ZmJlOWQyMDg4YjZkM2NkYzNkYSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ4LjQwMTg1NzEyMDE4NzM1LCA5LjYwMDE4MTIyMzQwMDk0M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAicm95YWxibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogInJveWFsYmx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfNTQyYWRlZGYwYjVjNDAwMmI0OWI1NTZmMjlhOWJjYmMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzNiOTAyYTIxMDM1OTQ4ZTlhZDZjMjlhNTFhYWQxNGE0ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8zYjA1Njg1MzI0ZTQ0ZmE4OTk0YWYyOWZlOWViY2UyOCA9ICQoYDxkaXYgaWQ9Imh0bWxfM2IwNTY4NTMyNGU0NGZhODk5NGFmMjlmZTllYmNlMjgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzNiOTAyYTIxMDM1OTQ4ZTlhZDZjMjlhNTFhYWQxNGE0LnNldENvbnRlbnQoaHRtbF8zYjA1Njg1MzI0ZTQ0ZmE4OTk0YWYyOWZlOWViY2UyOCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYWFlZjNlNmM0OGI5NGZiZTlkMjA4OGI2ZDNjZGMzZGEuYmluZFBvcHVwKHBvcHVwXzNiOTAyYTIxMDM1OTQ4ZTlhZDZjMjlhNTFhYWQxNGE0KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zNzFlODliZTVkYzI0Y2Y4ODg2YzExOWU2N2MzNmM0YSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ4LjAxNzk1ODUzMzUxMzQ3LCA5LjI0MjEzODk1NzI0ODQ1NF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAicm95YWxibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogInJveWFsYmx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfNTQyYWRlZGYwYjVjNDAwMmI0OWI1NTZmMjlhOWJjYmMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzcyNGM1YTY5NWRiMDQzMWM5NjZkMjNlNmE5YzczMTcwID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9hOGJiMjMwOTIzNzY0MGQzYmU2NjEyODQ0OWVjNGY3MiA9ICQoYDxkaXYgaWQ9Imh0bWxfYThiYjIzMDkyMzc2NDBkM2JlNjYxMjg0NDllYzRmNzIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzcyNGM1YTY5NWRiMDQzMWM5NjZkMjNlNmE5YzczMTcwLnNldENvbnRlbnQoaHRtbF9hOGJiMjMwOTIzNzY0MGQzYmU2NjEyODQ0OWVjNGY3Mik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMzcxZTg5YmU1ZGMyNGNmODg4NmMxMTllNjdjMzZjNGEuYmluZFBvcHVwKHBvcHVwXzcyNGM1YTY5NWRiMDQzMWM5NjZkMjNlNmE5YzczMTcwKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lMDY0Mzg3OGRlOGM0NTU1ODc3MDQ3YjY2Y2JmYWY4ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ4LjEyNjkzMzg1NDUzNjgzLCA5LjQ4MzkwNjA4NTExNTc2Nl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAicm95YWxibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogInJveWFsYmx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfNTQyYWRlZGYwYjVjNDAwMmI0OWI1NTZmMjlhOWJjYmMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzk0MDFlNWU3OWJjYTQ0Mzg4MWViNDNkOTNkNmZkOGFiID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82MTQ1ZjdkZjRlN2Q0OWIyYWFiM2IzZGI2MzA4NjI5ZSA9ICQoYDxkaXYgaWQ9Imh0bWxfNjE0NWY3ZGY0ZTdkNDliMmFhYjNiM2RiNjMwODYyOWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzk0MDFlNWU3OWJjYTQ0Mzg4MWViNDNkOTNkNmZkOGFiLnNldENvbnRlbnQoaHRtbF82MTQ1ZjdkZjRlN2Q0OWIyYWFiM2IzZGI2MzA4NjI5ZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZTA2NDM4NzhkZThjNDU1NTg3NzA0N2I2NmNiZmFmOGQuYmluZFBvcHVwKHBvcHVwXzk0MDFlNWU3OWJjYTQ0Mzg4MWViNDNkOTNkNmZkOGFiKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84MzdhMThlNjU2OTY0N2JmYWEwOWFhNDBiYWI5NTM2YiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ4LjY3OTM4ODQyOTUzNzA1NiwgOS4yOTQyNjgxMjQyMjkzMzNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzU0MmFkZWRmMGI1YzQwMDJiNDliNTU2ZjI5YTliY2JjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hOTViM2I5NmI0YzY0OGQzYmRiOGQyN2Q4YzhhYjU2ZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZWQ4ZjQ1NTcyMWY5NDk1MTk2NTFkMGZhOWMyOWNhYjUgPSAkKGA8ZGl2IGlkPSJodG1sX2VkOGY0NTU3MjFmOTQ5NTE5NjUxZDBmYTljMjljYWI1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hOTViM2I5NmI0YzY0OGQzYmRiOGQyN2Q4YzhhYjU2ZC5zZXRDb250ZW50KGh0bWxfZWQ4ZjQ1NTcyMWY5NDk1MTk2NTFkMGZhOWMyOWNhYjUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzgzN2ExOGU2NTY5NjQ3YmZhYTA5YWE0MGJhYjk1MzZiLmJpbmRQb3B1cChwb3B1cF9hOTViM2I5NmI0YzY0OGQzYmRiOGQyN2Q4YzhhYjU2ZCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDYxYTdkNDBmODdhNDMxYjlkOGY0ZDY2NjJhNmI1YmYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC4zMDg1MDA3MzgwMTcwNDUsIDkuNDkwMjk5MDk1MzQ4ODA1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF81NDJhZGVkZjBiNWM0MDAyYjQ5YjU1NmYyOWE5YmNiYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOWMwM2IzZTVmMWM0NGY3NTg5NWE3NTFiM2RhMzI4NjEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzgxYWY4NzhkZjA0YzQ5MDRiNDc5MmJjY2JlNGUyMmE5ID0gJChgPGRpdiBpZD0iaHRtbF84MWFmODc4ZGYwNGM0OTA0YjQ3OTJiY2NiZTRlMjJhOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOWMwM2IzZTVmMWM0NGY3NTg5NWE3NTFiM2RhMzI4NjEuc2V0Q29udGVudChodG1sXzgxYWY4NzhkZjA0YzQ5MDRiNDc5MmJjY2JlNGUyMmE5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl80NjFhN2Q0MGY4N2E0MzFiOWQ4ZjRkNjY2MmE2YjViZi5iaW5kUG9wdXAocG9wdXBfOWMwM2IzZTVmMWM0NGY3NTg5NWE3NTFiM2RhMzI4NjEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U5Y2ZiOTZmODVlYTQ1MTU5NzU1ZDhmZTgyMDU4YTc0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguMjMxMjc5MTMxODQyNTksIDkuNDU3NjI5MDAwNDUxMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzU0MmFkZWRmMGI1YzQwMDJiNDliNTU2ZjI5YTliY2JjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9mYTI1MGE1NTM0YWI0YWY5YjQ2NzMwOThiNTY1MTY1YyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjBkMGYwNmE5NmVkNDAzMGE2OWZiMDljNDAwM2RlZDEgPSAkKGA8ZGl2IGlkPSJodG1sXzYwZDBmMDZhOTZlZDQwMzBhNjlmYjA5YzQwMDNkZWQxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9mYTI1MGE1NTM0YWI0YWY5YjQ2NzMwOThiNTY1MTY1Yy5zZXRDb250ZW50KGh0bWxfNjBkMGYwNmE5NmVkNDAzMGE2OWZiMDljNDAwM2RlZDEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U5Y2ZiOTZmODVlYTQ1MTU5NzU1ZDhmZTgyMDU4YTc0LmJpbmRQb3B1cChwb3B1cF9mYTI1MGE1NTM0YWI0YWY5YjQ2NzMwOThiNTY1MTY1YykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfODM0MDU2OTBkN2QzNDA4MmI0MmQ0MjNmMDQ0YmFkMjEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC4zNzgzOTY2MjE4ODcxMywgOS40NzA3OTcyMDg4Mjg3MzFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzU0MmFkZWRmMGI1YzQwMDJiNDliNTU2ZjI5YTliY2JjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9jNWQ0NjJlNGExN2M0NjY2YjEyYTI0NzgyNjNlY2QzYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOWJhNDNiNmEzZmI2NDU3Yzg1OTM1MjA0NGI4MGUzNGEgPSAkKGA8ZGl2IGlkPSJodG1sXzliYTQzYjZhM2ZiNjQ1N2M4NTkzNTIwNDRiODBlMzRhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9jNWQ0NjJlNGExN2M0NjY2YjEyYTI0NzgyNjNlY2QzYS5zZXRDb250ZW50KGh0bWxfOWJhNDNiNmEzZmI2NDU3Yzg1OTM1MjA0NGI4MGUzNGEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzgzNDA1NjkwZDdkMzQwODJiNDJkNDIzZjA0NGJhZDIxLmJpbmRQb3B1cChwb3B1cF9jNWQ0NjJlNGExN2M0NjY2YjEyYTI0NzgyNjNlY2QzYSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOTNhZWRhNjlkZDdmNDhkM2IzNjU5ZjI1MzVhMDIxNmIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC43ODY1ODM3MjQyMDg3LCA5LjEyNzkzODExNDg1MzcyNV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAicm95YWxibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogInJveWFsYmx1ZSIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfNTQyYWRlZGYwYjVjNDAwMmI0OWI1NTZmMjlhOWJjYmMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2Q1OTllYmQzYWFlMDQ5MjViNDU4OTExODRjMDAyMDY3ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF83ZjgzOTE2ZDM3NDg0NmM0OGYyYjI0NTA4ZmM1NjdiNiA9ICQoYDxkaXYgaWQ9Imh0bWxfN2Y4MzkxNmQzNzQ4NDZjNDhmMmIyNDUwOGZjNTY3YjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGNvbnZleCBodWxsPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2Q1OTllYmQzYWFlMDQ5MjViNDU4OTExODRjMDAyMDY3LnNldENvbnRlbnQoaHRtbF83ZjgzOTE2ZDM3NDg0NmM0OGYyYjI0NTA4ZmM1NjdiNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfOTNhZWRhNjlkZDdmNDhkM2IzNjU5ZjI1MzVhMDIxNmIuYmluZFBvcHVwKHBvcHVwX2Q1OTllYmQzYWFlMDQ5MjViNDU4OTExODRjMDAyMDY3KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgbGF5ZXJfY29udHJvbF9iODBhNWNjNThlMGU0YzRiOGUwNjA4ZjM5YTI2ZDgzOSA9IHsKICAgICAgICAgICAgICAgIGJhc2VfbGF5ZXJzIDogewogICAgICAgICAgICAgICAgICAgICJvcGVuc3RyZWV0bWFwIiA6IHRpbGVfbGF5ZXJfYTUxNWZmYzEyNjU3NDA1YjhhNThiMTU2ZWYxYjA4Y2EsCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgb3ZlcmxheXMgOiAgewogICAgICAgICAgICAgICAgICAgICJFeGFtcGxlIGNvbnZleCBodWxsIiA6IGZlYXR1cmVfZ3JvdXBfZWE1MTc4NDlkZjZhNDlkMjg5ODg4ZTEyM2YxNGQyYzcsCiAgICAgICAgICAgICAgICAgICAgIkV4YW1wbGUgcG9pbnRzIGZvciBjb252ZXggaHVsbCIgOiBmZWF0dXJlX2dyb3VwXzU0MmFkZWRmMGI1YzQwMDJiNDliNTU2ZjI5YTliY2JjLAogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgTC5jb250cm9sLmxheWVycygKICAgICAgICAgICAgICAgIGxheWVyX2NvbnRyb2xfYjgwYTVjYzU4ZTBlNGM0YjhlMDYwOGYzOWEyNmQ4MzkuYmFzZV9sYXllcnMsCiAgICAgICAgICAgICAgICBsYXllcl9jb250cm9sX2I4MGE1Y2M1OGUwZTRjNGI4ZTA2MDhmMzlhMjZkODM5Lm92ZXJsYXlzLAogICAgICAgICAgICAgICAgeyJhdXRvWkluZGV4IjogdHJ1ZSwgImNvbGxhcHNlZCI6IGZhbHNlLCAicG9zaXRpb24iOiAidG9wcmlnaHQifQogICAgICAgICAgICApLmFkZFRvKG1hcF82ZDM5NDlkZTdjZDE0NTE2YTM4OGMzYTFlM2E0MjMyMCk7CiAgICAgICAgCjwvc2NyaXB0Pg== onload=\"this.contentDocument.open();this.contentDocument.write(atob(this.getAttribute('data-html')));this.contentDocument.close();\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ],
      "text/plain": [
       "<folium.folium.Map at 0x7f9a7c4db9a0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Initialize map\n",
    "my_convexhull_map = folium.Map(location=[48.5, 9.5], zoom_start=8)\n",
    "\n",
    "# Create a convex hull polygon that contains some points\n",
    "list_of_points = randome_points(\n",
    "    amount=10, LON_min=48, LON_max=49, LAT_min=9, LAT_max=10\n",
    ")\n",
    "\n",
    "create_convexhull_polygon(\n",
    "    my_convexhull_map,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example convex hull\",\n",
    "    line_color=\"lightblue\",\n",
    "    fill_color=\"lightskyblue\",\n",
    "    weight=5,\n",
    "    text=\"Example convex hull\",\n",
    ")\n",
    "\n",
    "draw_points(\n",
    "    my_convexhull_map,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example points for convex hull\",\n",
    "    line_color=\"royalblue\",\n",
    "    fill_color=\"royalblue\",\n",
    "    text=\"Example point for convex hull\",\n",
    ")\n",
    "\n",
    "# Add layer control and show map\n",
    "folium.LayerControl(collapsed=False).add_to(my_convexhull_map)\n",
    "my_convexhull_map"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Envelope\n",
    "\n",
    "The envelope is another interesting approach - its goal is to create a box that contains all points from a given list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_envelope_polygon(\n",
    "    map_object, list_of_points, layer_name, line_color, fill_color, weight, text\n",
    "):\n",
    "\n",
    "    # Since it is pointless to draw a box around less than 2 points check len of input\n",
    "    if len(list_of_points) < 2:\n",
    "        return\n",
    "\n",
    "    # Find the edges of box\n",
    "    from operator import itemgetter\n",
    "\n",
    "    list_of_points = sorted(list_of_points, key=itemgetter(0))\n",
    "    x_min = list_of_points[0]\n",
    "    x_max = list_of_points[len(list_of_points) - 1]\n",
    "\n",
    "    list_of_points = sorted(list_of_points, key=itemgetter(1))\n",
    "    y_min = list_of_points[0]\n",
    "    y_max = list_of_points[len(list_of_points) - 1]\n",
    "\n",
    "    upper_left = (x_min[0], y_max[1])\n",
    "    upper_right = (x_max[0], y_max[1])\n",
    "    lower_right = (x_max[0], y_min[1])\n",
    "    lower_left = (x_min[0], y_min[1])\n",
    "\n",
    "    edges = [upper_left, upper_right, lower_right, lower_left]\n",
    "\n",
    "    # Create feature group, add the polygon and add the feature group to the map\n",
    "    fg = folium.FeatureGroup(name=layer_name)\n",
    "    fg.add_child(\n",
    "        folium.vector_layers.Polygon(\n",
    "            locations=edges,\n",
    "            color=line_color,\n",
    "            fill_color=fill_color,\n",
    "            weight=weight,\n",
    "            popup=(folium.Popup(text)),\n",
    "        )\n",
    "    )\n",
    "    map_object.add_child(fg)\n",
    "\n",
    "    return map_object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe src=\"about:blank\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" data-html=PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgCiAgICAgICAgPHNjcmlwdD4KICAgICAgICAgICAgTF9OT19UT1VDSCA9IGZhbHNlOwogICAgICAgICAgICBMX0RJU0FCTEVfM0QgPSBmYWxzZTsKICAgICAgICA8L3NjcmlwdD4KICAgIAogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NvZGUuanF1ZXJ5LmNvbS9qcXVlcnktMS4xMi40Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUubWluLmNzcyIvPgogICAgCiAgICAgICAgICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsCiAgICAgICAgICAgICAgICBpbml0aWFsLXNjYWxlPTEuMCwgbWF4aW11bS1zY2FsZT0xLjAsIHVzZXItc2NhbGFibGU9bm8iIC8+CiAgICAgICAgICAgIDxzdHlsZT4KICAgICAgICAgICAgICAgICNtYXBfZDlkNmFjNWJhYjVkNDJkNGE1NjUzZGQ2YWY5YzgyZWEgewogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGhlaWdodDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGxlZnQ6IDAuMCU7CiAgICAgICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwX2Q5ZDZhYzViYWI1ZDQyZDRhNTY1M2RkNmFmOWM4MmVhIiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKICAgICAgICAgICAgdmFyIG1hcF9kOWQ2YWM1YmFiNWQ0MmQ0YTU2NTNkZDZhZjljODJlYSA9IEwubWFwKAogICAgICAgICAgICAgICAgIm1hcF9kOWQ2YWM1YmFiNWQ0MmQ0YTU2NTNkZDZhZjljODJlYSIsCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgY2VudGVyOiBbNDkuNSwgOC41XSwKICAgICAgICAgICAgICAgICAgICBjcnM6IEwuQ1JTLkVQU0czODU3LAogICAgICAgICAgICAgICAgICAgIHpvb206IDgsCiAgICAgICAgICAgICAgICAgICAgem9vbUNvbnRyb2w6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgcHJlZmVyQ2FudmFzOiBmYWxzZSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIAoKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl8wZjVjN2RiMjIyZmQ0OWY1YWJhMzFmMjFhMGI1NTY1MCA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgImh0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nIiwKICAgICAgICAgICAgICAgIHsiYXR0cmlidXRpb24iOiAiRGF0YSBieSBcdTAwMjZjb3B5OyBcdTAwM2NhIGhyZWY9XCJodHRwOi8vb3BlbnN0cmVldG1hcC5vcmdcIlx1MDAzZU9wZW5TdHJlZXRNYXBcdTAwM2MvYVx1MDAzZSwgdW5kZXIgXHUwMDNjYSBocmVmPVwiaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIlx1MDAzZU9EYkxcdTAwM2MvYVx1MDAzZS4iLCAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsICJtYXhOYXRpdmVab29tIjogMTgsICJtYXhab29tIjogMTgsICJtaW5ab29tIjogMCwgIm5vV3JhcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEsICJzdWJkb21haW5zIjogImFiYyIsICJ0bXMiOiBmYWxzZX0KICAgICAgICAgICAgKS5hZGRUbyhtYXBfZDlkNmFjNWJhYjVkNDJkNGE1NjUzZGQ2YWY5YzgyZWEpOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwXzIyNzZhNGRmMGY2OTQ4ZGE4YjA1ODBhMjVhNzVlYzk5ID0gTC5mZWF0dXJlR3JvdXAoCiAgICAgICAgICAgICAgICB7fQogICAgICAgICAgICApLmFkZFRvKG1hcF9kOWQ2YWM1YmFiNWQ0MmQ0YTU2NTNkZDZhZjljODJlYSk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvbHlnb25fZDQwNzNiZDJmZWU3NDdjNGJhMzA2NzFkYWU1NTQ2NDggPSBMLnBvbHlnb24oCiAgICAgICAgICAgICAgICBbWzQ5LjE0Njc1OTM4NzQ2MzcxLCA4LjkzNTkxMzYyNzQ5MDc3N10sIFs0OS45NDIwMzAwNTAwNzk2NSwgOC45MzU5MTM2Mjc0OTA3NzddLCBbNDkuOTQyMDMwMDUwMDc5NjUsIDguMDI5MTE5Njc2NDY0NThdLCBbNDkuMTQ2NzU5Mzg3NDYzNzEsIDguMDI5MTE5Njc2NDY0NThdXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJpbmRpYW5yZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm5vQ2xpcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEuMCwgInNtb290aEZhY3RvciI6IDEuMCwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiA1fQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfMjI3NmE0ZGYwZjY5NDhkYThiMDU4MGEyNWE3NWVjOTkpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzBkY2FjOGE4MzgxNTRiYjc4OGJlYjQ0MjUxNDc4NmJkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wNmFlM2NmMmE4Yjc0NzJiYjk2ODY4N2YxNTI3ZGQ0YSA9ICQoYDxkaXYgaWQ9Imh0bWxfMDZhZTNjZjJhOGI3NDcyYmI5Njg2ODdmMTUyN2RkNGEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMGRjYWM4YTgzODE1NGJiNzg4YmViNDQyNTE0Nzg2YmQuc2V0Q29udGVudChodG1sXzA2YWUzY2YyYThiNzQ3MmJiOTY4Njg3ZjE1MjdkZDRhKTsKICAgICAgICAKCiAgICAgICAgcG9seWdvbl9kNDA3M2JkMmZlZTc0N2M0YmEzMDY3MWRhZTU1NDY0OC5iaW5kUG9wdXAocG9wdXBfMGRjYWM4YTgzODE1NGJiNzg4YmViNDQyNTE0Nzg2YmQpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwXzliMjc1MDUzNDIwYzQ3MzU5NzMwZTE1MDQzYTY2NTExID0gTC5mZWF0dXJlR3JvdXAoCiAgICAgICAgICAgICAgICB7fQogICAgICAgICAgICApLmFkZFRvKG1hcF9kOWQ2YWM1YmFiNWQ0MmQ0YTU2NTNkZDZhZjljODJlYSk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYTFmYjAzMzBkNWU5NDVmNzliZDc1YTNkMDQ2NWE0ZjIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS42MTM5MjcxODgzODc5LCA4LjA5OTQ1NjU4MDg4MzQ0XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzliMjc1MDUzNDIwYzQ3MzU5NzMwZTE1MDQzYTY2NTExKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yNzkzODE4N2I1MDg0OWQ2YjM4YzJjMjU4YTVjNDVlYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMzRiNDY2MWIzMTQ3NDYzYjlkZjlkOGJkOGMwNjczNWMgPSAkKGA8ZGl2IGlkPSJodG1sXzM0YjQ2NjFiMzE0NzQ2M2I5ZGY5ZDhiZDhjMDY3MzVjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yNzkzODE4N2I1MDg0OWQ2YjM4YzJjMjU4YTVjNDVlYS5zZXRDb250ZW50KGh0bWxfMzRiNDY2MWIzMTQ3NDYzYjlkZjlkOGJkOGMwNjczNWMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ExZmIwMzMwZDVlOTQ1Zjc5YmQ3NWEzZDA0NjVhNGYyLmJpbmRQb3B1cChwb3B1cF8yNzkzODE4N2I1MDg0OWQ2YjM4YzJjMjU4YTVjNDVlYSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzFjZDQxZTI1OGJlNDRjMTgyZGQ4NWM1MmNhYjllNzggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS44NDYwMjk5MzEzNTAzMSwgOC41ODA4NjExOTM2Njc1MTVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfOWIyNzUwNTM0MjBjNDczNTk3MzBlMTUwNDNhNjY1MTEpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzg2OWM0NWMwN2NmYTQyOTQ4MjBkN2ZhYWViZjU5ZmU0ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iOGFlMDI3M2I4NDI0OWJhOTVhMmRkNGE4ZDQ2MDg3ZiA9ICQoYDxkaXYgaWQ9Imh0bWxfYjhhZTAyNzNiODQyNDliYTk1YTJkZDRhOGQ0NjA4N2YiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzg2OWM0NWMwN2NmYTQyOTQ4MjBkN2ZhYWViZjU5ZmU0LnNldENvbnRlbnQoaHRtbF9iOGFlMDI3M2I4NDI0OWJhOTVhMmRkNGE4ZDQ2MDg3Zik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYzFjZDQxZTI1OGJlNDRjMTgyZGQ4NWM1MmNhYjllNzguYmluZFBvcHVwKHBvcHVwXzg2OWM0NWMwN2NmYTQyOTQ4MjBkN2ZhYWViZjU5ZmU0KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wMTEwZGUxNDM0MTY0ZTFkYmZkOGU0ZjQ4YzljM2E0YiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5LjE1MzE3NjIzNjM2NjAxLCA4LjEzMjAzNjgxNzg4MTI0XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzliMjc1MDUzNDIwYzQ3MzU5NzMwZTE1MDQzYTY2NTExKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80NTkzM2RiODg1YjM0MTMyYTNmMzg1NGU2ODdkNmE4YiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOTNmMmM3YWYzZTI0NDdmNThiMTJjNGYyM2Q2ZThhNmEgPSAkKGA8ZGl2IGlkPSJodG1sXzkzZjJjN2FmM2UyNDQ3ZjU4YjEyYzRmMjNkNmU4YTZhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80NTkzM2RiODg1YjM0MTMyYTNmMzg1NGU2ODdkNmE4Yi5zZXRDb250ZW50KGh0bWxfOTNmMmM3YWYzZTI0NDdmNThiMTJjNGYyM2Q2ZThhNmEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzAxMTBkZTE0MzQxNjRlMWRiZmQ4ZTRmNDhjOWMzYTRiLmJpbmRQb3B1cChwb3B1cF80NTkzM2RiODg1YjM0MTMyYTNmMzg1NGU2ODdkNmE4YikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGNmMzY0NWVkN2E5NDNiOTg4Zjc0NTQ3Y2YzMTlkZWYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS45MzA1Njk5MjcxOTM4OSwgOC42NDc1NzY3ODQ1OTkyNDNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfOWIyNzUwNTM0MjBjNDczNTk3MzBlMTUwNDNhNjY1MTEpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2ZjNGJjOWI2Mjk5MTQwOWY4ZDVlY2U1ZmE3NTc0NDEwID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wZjA2YmZlODE3ZGU0Y2I3OTVmYjZiYTRmZjYxZWJiNiA9ICQoYDxkaXYgaWQ9Imh0bWxfMGYwNmJmZTgxN2RlNGNiNzk1ZmI2YmE0ZmY2MWViYjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2ZjNGJjOWI2Mjk5MTQwOWY4ZDVlY2U1ZmE3NTc0NDEwLnNldENvbnRlbnQoaHRtbF8wZjA2YmZlODE3ZGU0Y2I3OTVmYjZiYTRmZjYxZWJiNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNGNmMzY0NWVkN2E5NDNiOTg4Zjc0NTQ3Y2YzMTlkZWYuYmluZFBvcHVwKHBvcHVwX2ZjNGJjOWI2Mjk5MTQwOWY4ZDVlY2U1ZmE3NTc0NDEwKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zYjk4NGNhZTJjMWE0OWIxYTQwMTYyZGU4OGFhMWNkNCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5Ljk0MjAzMDA1MDA3OTY1LCA4LjM0NjI2NDE4NTQ5NzUyM10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF85YjI3NTA1MzQyMGM0NzM1OTczMGUxNTA0M2E2NjUxMSk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYWEyY2RhM2NlMjMwNDU1Yjk4ZDFkNzNiOGEwNzVhNmMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2U0MDJjOTFlYWEwYTRlYmViNTU2NDk2Y2IyZWNiNWU5ID0gJChgPGRpdiBpZD0iaHRtbF9lNDAyYzkxZWFhMGE0ZWJlYjU1NjQ5NmNiMmVjYjVlOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYWEyY2RhM2NlMjMwNDU1Yjk4ZDFkNzNiOGEwNzVhNmMuc2V0Q29udGVudChodG1sX2U0MDJjOTFlYWEwYTRlYmViNTU2NDk2Y2IyZWNiNWU5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zYjk4NGNhZTJjMWE0OWIxYTQwMTYyZGU4OGFhMWNkNC5iaW5kUG9wdXAocG9wdXBfYWEyY2RhM2NlMjMwNDU1Yjk4ZDFkNzNiOGEwNzVhNmMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y4YTExY2Y5NjM2NjQyNjM5NDhmZTU3MWFmOWY5YmQ3ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuNjIwNzc2NjQxMDUzOTY1LCA4LjUxMjkwNjk3MjAzMzFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfOWIyNzUwNTM0MjBjNDczNTk3MzBlMTUwNDNhNjY1MTEpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzdkMzU5MWQyOWQzMzRhNjA5YjMyNjVhNzhlZWVlZDU1ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mNzQzODMxMTFlNTc0ZjM0OGZiNTVhNzg3ODQ5YWJmMCA9ICQoYDxkaXYgaWQ9Imh0bWxfZjc0MzgzMTExZTU3NGYzNDhmYjU1YTc4Nzg0OWFiZjAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzdkMzU5MWQyOWQzMzRhNjA5YjMyNjVhNzhlZWVlZDU1LnNldENvbnRlbnQoaHRtbF9mNzQzODMxMTFlNTc0ZjM0OGZiNTVhNzg3ODQ5YWJmMCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZjhhMTFjZjk2MzY2NDI2Mzk0OGZlNTcxYWY5ZjliZDcuYmluZFBvcHVwKHBvcHVwXzdkMzU5MWQyOWQzMzRhNjA5YjMyNjVhNzhlZWVlZDU1KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kODEyZTNlNzlkZGE0NzA2YTJkYjFmZWQ5ZTM5MzRjZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5LjgzNDc1NjYzNTMzMTc5LCA4LjM5Njc0NzY0MDMxMzEzNF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF85YjI3NTA1MzQyMGM0NzM1OTczMGUxNTA0M2E2NjUxMSk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZjlkNjJkMTU2NTQ5NGU4NjlhNTE2ZTVmMTZhYzM3YjAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzZkY2FjOWUyYWFmYjQ0YWVhMzhkM2Y5NTlhYjNhM2E3ID0gJChgPGRpdiBpZD0iaHRtbF82ZGNhYzllMmFhZmI0NGFlYTM4ZDNmOTU5YWIzYTNhNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZjlkNjJkMTU2NTQ5NGU4NjlhNTE2ZTVmMTZhYzM3YjAuc2V0Q29udGVudChodG1sXzZkY2FjOWUyYWFmYjQ0YWVhMzhkM2Y5NTlhYjNhM2E3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kODEyZTNlNzlkZGE0NzA2YTJkYjFmZWQ5ZTM5MzRjZi5iaW5kUG9wdXAocG9wdXBfZjlkNjJkMTU2NTQ5NGU4NjlhNTE2ZTVmMTZhYzM3YjApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2M5NGNjMjQzNDA2ODQ5OTNhZDYzNzQ5NjhlMWE4Y2FlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuMTQ2NzU5Mzg3NDYzNzEsIDguMDI5MTE5Njc2NDY0NThdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfOWIyNzUwNTM0MjBjNDczNTk3MzBlMTUwNDNhNjY1MTEpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzk1NmEyOGRiMmU0MTRhZTNhOWIwMWIwYzFkN2Q1MmRkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9lNWM0ZDVjOWY0ZWE0YTZhODgzOTM3MzhhMWE5YzBmNCA9ICQoYDxkaXYgaWQ9Imh0bWxfZTVjNGQ1YzlmNGVhNGE2YTg4MzkzNzM4YTFhOWMwZjQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzk1NmEyOGRiMmU0MTRhZTNhOWIwMWIwYzFkN2Q1MmRkLnNldENvbnRlbnQoaHRtbF9lNWM0ZDVjOWY0ZWE0YTZhODgzOTM3MzhhMWE5YzBmNCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYzk0Y2MyNDM0MDY4NDk5M2FkNjM3NDk2OGUxYThjYWUuYmluZFBvcHVwKHBvcHVwXzk1NmEyOGRiMmU0MTRhZTNhOWIwMWIwYzFkN2Q1MmRkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zZDIyODliODUwYzY0MjUyYWQzMWRkZDZhYWNhZmZjZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5LjIwNjY4NTM3NjI0NDc1LCA4LjkzNTkxMzYyNzQ5MDc3N10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF85YjI3NTA1MzQyMGM0NzM1OTczMGUxNTA0M2E2NjUxMSk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZjI0YzgwMzkxMDI3NDNjN2JmZWVlNzQxOGMwZjI3NzAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzA1MDRhNDBlZjg5MjQ5NjQ4NTYzODRiZTQ0MjI2YTFjID0gJChgPGRpdiBpZD0iaHRtbF8wNTA0YTQwZWY4OTI0OTY0ODU2Mzg0YmU0NDIyNmExYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZjI0YzgwMzkxMDI3NDNjN2JmZWVlNzQxOGMwZjI3NzAuc2V0Q29udGVudChodG1sXzA1MDRhNDBlZjg5MjQ5NjQ4NTYzODRiZTQ0MjI2YTFjKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zZDIyODliODUwYzY0MjUyYWQzMWRkZDZhYWNhZmZjZi5iaW5kUG9wdXAocG9wdXBfZjI0YzgwMzkxMDI3NDNjN2JmZWVlNzQxOGMwZjI3NzApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IyMjc3NWZmMjJjZTQzYmU5MDQ1OGEzODViOTdiYTliID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuNTMwMDU0MjM2NjcxNTUsIDguMTM5NTI1OTQ3NDg2NjUzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzliMjc1MDUzNDIwYzQ3MzU5NzMwZTE1MDQzYTY2NTExKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80M2I0YmM2OTQ5NWE0MjY0OWYyNmQ5NzI3NDdkZTM1NSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYzZkY2ExMTIyNTQyNGIyN2E4MjlkYzNiNzA2Njc2ZWIgPSAkKGA8ZGl2IGlkPSJodG1sX2M2ZGNhMTEyMjU0MjRiMjdhODI5ZGMzYjcwNjY3NmViIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80M2I0YmM2OTQ5NWE0MjY0OWYyNmQ5NzI3NDdkZTM1NS5zZXRDb250ZW50KGh0bWxfYzZkY2ExMTIyNTQyNGIyN2E4MjlkYzNiNzA2Njc2ZWIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2IyMjc3NWZmMjJjZTQzYmU5MDQ1OGEzODViOTdiYTliLmJpbmRQb3B1cChwb3B1cF80M2I0YmM2OTQ5NWE0MjY0OWYyNmQ5NzI3NDdkZTM1NSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGxheWVyX2NvbnRyb2xfNDYxMDZlMDlkZTlmNGMzMDk5MzAxNGIwMjU5MDAyMTEgPSB7CiAgICAgICAgICAgICAgICBiYXNlX2xheWVycyA6IHsKICAgICAgICAgICAgICAgICAgICAib3BlbnN0cmVldG1hcCIgOiB0aWxlX2xheWVyXzBmNWM3ZGIyMjJmZDQ5ZjVhYmEzMWYyMWEwYjU1NjUwLAogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIG92ZXJsYXlzIDogIHsKICAgICAgICAgICAgICAgICAgICAiRXhhbXBsZSBlbnZlbG9wZSIgOiBmZWF0dXJlX2dyb3VwXzIyNzZhNGRmMGY2OTQ4ZGE4YjA1ODBhMjVhNzVlYzk5LAogICAgICAgICAgICAgICAgICAgICJFeGFtcGxlIHBvaW50cyBmb3IgZW52ZWxvcGUiIDogZmVhdHVyZV9ncm91cF85YjI3NTA1MzQyMGM0NzM1OTczMGUxNTA0M2E2NjUxMSwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIEwuY29udHJvbC5sYXllcnMoCiAgICAgICAgICAgICAgICBsYXllcl9jb250cm9sXzQ2MTA2ZTA5ZGU5ZjRjMzA5OTMwMTRiMDI1OTAwMjExLmJhc2VfbGF5ZXJzLAogICAgICAgICAgICAgICAgbGF5ZXJfY29udHJvbF80NjEwNmUwOWRlOWY0YzMwOTkzMDE0YjAyNTkwMDIxMS5vdmVybGF5cywKICAgICAgICAgICAgICAgIHsiYXV0b1pJbmRleCI6IHRydWUsICJjb2xsYXBzZWQiOiBmYWxzZSwgInBvc2l0aW9uIjogInRvcHJpZ2h0In0KICAgICAgICAgICAgKS5hZGRUbyhtYXBfZDlkNmFjNWJhYjVkNDJkNGE1NjUzZGQ2YWY5YzgyZWEpOwogICAgICAgIAo8L3NjcmlwdD4= onload=\"this.contentDocument.open();this.contentDocument.write(atob(this.getAttribute('data-html')));this.contentDocument.close();\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ],
      "text/plain": [
       "<folium.folium.Map at 0x7f9a2140dd00>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Initialize map\n",
    "my_envelope_map = folium.Map(location=[49.5, 8.5], zoom_start=8)\n",
    "\n",
    "# Create an envelope polygon that contains some points\n",
    "list_of_points = randome_points(\n",
    "    amount=10, LON_min=49.1, LON_max=50, LAT_min=8, LAT_max=9\n",
    ")\n",
    "\n",
    "create_envelope_polygon(\n",
    "    my_envelope_map,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example envelope\",\n",
    "    line_color=\"indianred\",\n",
    "    fill_color=\"red\",\n",
    "    weight=5,\n",
    "    text=\"Example envelope\",\n",
    ")\n",
    "\n",
    "draw_points(\n",
    "    my_envelope_map,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example points for envelope\",\n",
    "    line_color=\"darkred\",\n",
    "    fill_color=\"darkred\",\n",
    "    text=\"Example point for envelope\",\n",
    ")\n",
    "\n",
    "# Add layer control and show map\n",
    "folium.LayerControl(collapsed=False).add_to(my_envelope_map)\n",
    "my_envelope_map"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Concave hull (alpha shape)\n",
    "In some cases the convex hull does not yield good results - this is when the shape of the polygon should be concave instead of convex. The solution is a concave hull that is also called alpha shape. Yet, there is no ready to go, off the shelve solution for this but there are great resources (see: http://blog.thehumangeo.com/2014/05/12/drawing-boundaries-in-python/, accessed 04.01.2019 or https://towardsdatascience.com/the-concave-hull-c649795c0f0f, accessed 29.12.2018)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Main code\n",
    "Just putting it all together..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe src=\"about:blank\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" data-html=PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgCiAgICAgICAgPHNjcmlwdD4KICAgICAgICAgICAgTF9OT19UT1VDSCA9IGZhbHNlOwogICAgICAgICAgICBMX0RJU0FCTEVfM0QgPSBmYWxzZTsKICAgICAgICA8L3NjcmlwdD4KICAgIAogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NvZGUuanF1ZXJ5LmNvbS9qcXVlcnktMS4xMi40Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS42LjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUubWluLmNzcyIvPgogICAgCiAgICAgICAgICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsCiAgICAgICAgICAgICAgICBpbml0aWFsLXNjYWxlPTEuMCwgbWF4aW11bS1zY2FsZT0xLjAsIHVzZXItc2NhbGFibGU9bm8iIC8+CiAgICAgICAgICAgIDxzdHlsZT4KICAgICAgICAgICAgICAgICNtYXBfNjc5NDM5NzE5ZjcyNDRjMjlhYWQ5ZjNhMWNmNzJhYWEgewogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGhlaWdodDogMTAwLjAlOwogICAgICAgICAgICAgICAgICAgIGxlZnQ6IDAuMCU7CiAgICAgICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwXzY3OTQzOTcxOWY3MjQ0YzI5YWFkOWYzYTFjZjcyYWFhIiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKICAgICAgICAgICAgdmFyIG1hcF82Nzk0Mzk3MTlmNzI0NGMyOWFhZDlmM2ExY2Y3MmFhYSA9IEwubWFwKAogICAgICAgICAgICAgICAgIm1hcF82Nzk0Mzk3MTlmNzI0NGMyOWFhZDlmM2ExY2Y3MmFhYSIsCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgY2VudGVyOiBbNDguMjQ2MDY4MywgOS4yNjc2NDEyNV0sCiAgICAgICAgICAgICAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NywKICAgICAgICAgICAgICAgICAgICB6b29tOiA3LAogICAgICAgICAgICAgICAgICAgIHpvb21Db250cm9sOiB0cnVlLAogICAgICAgICAgICAgICAgICAgIHByZWZlckNhbnZhczogZmFsc2UsCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICk7CgogICAgICAgICAgICAKCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHRpbGVfbGF5ZXJfNzFiYTFhODFlN2Y2NDVlOGIyNzkxZGViNjVjOTZlMzggPSBMLnRpbGVMYXllcigKICAgICAgICAgICAgICAgICJodHRwczovL3tzfS50aWxlLm9wZW5zdHJlZXRtYXAub3JnL3t6fS97eH0ve3l9LnBuZyIsCiAgICAgICAgICAgICAgICB7ImF0dHJpYnV0aW9uIjogIkRhdGEgYnkgXHUwMDI2Y29weTsgXHUwMDNjYSBocmVmPVwiaHR0cDovL29wZW5zdHJlZXRtYXAub3JnXCJcdTAwM2VPcGVuU3RyZWV0TWFwXHUwMDNjL2FcdTAwM2UsIHVuZGVyIFx1MDAzY2EgaHJlZj1cImh0dHA6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvY29weXJpZ2h0XCJcdTAwM2VPRGJMXHUwMDNjL2FcdTAwM2UuIiwgImRldGVjdFJldGluYSI6IGZhbHNlLCAibWF4TmF0aXZlWm9vbSI6IDE4LCAibWF4Wm9vbSI6IDE4LCAibWluWm9vbSI6IDAsICJub1dyYXAiOiBmYWxzZSwgIm9wYWNpdHkiOiAxLCAic3ViZG9tYWlucyI6ICJhYmMiLCAidG1zIjogZmFsc2V9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzY3OTQzOTcxOWY3MjQ0YzI5YWFkOWYzYTFjZjcyYWFhKTsKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgZmVhdHVyZV9ncm91cF9jYWJhYWM5NzA4Mzk0ODQ2ODI1MTRkYmUyMjJjMzdhNyA9IEwuZmVhdHVyZUdyb3VwKAogICAgICAgICAgICAgICAge30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNjc5NDM5NzE5ZjcyNDRjMjlhYWQ5ZjNhMWNmNzJhYWEpOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb2x5Z29uXzJlYjY1YjA2NmY3ODRjNDBiMDBlOWEyYjJjNDFiZDNmID0gTC5wb2x5Z29uKAogICAgICAgICAgICAgICAgW1s0OC45Mzc1MzU2ODMwNDQzMywgOS41NDQ1NjY2NzQ1MjAzNF0sIFs0OC4yODkwNDE4ODU5NTAzOCwgOS45Njg3MjkwODI1ODY4MTRdLCBbNDguMTQ5MzE2NjM5MjUxNCwgOS44NzM4ODg4Nzk3OTAxOTddLCBbNDguMTE0MjE3NTIxMTA4Mzk0LCA5LjQ3MDU3Mzk5NDA2OTY5Nl0sIFs0OC42Mjc4Mjg5NzI0NTU2NDYsIDkuMjA1MjY2OTYzNTcwNjEyXSwgWzQ4LjgyNTEyNzc0MDQ0NzM5LCA5LjE5MTI1NDgxMTY0MzM0NV1dLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImxpZ2h0Ymx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJsaWdodHNreWJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAibm9DbGlwIjogZmFsc2UsICJvcGFjaXR5IjogMS4wLCAic21vb3RoRmFjdG9yIjogMS4wLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDV9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF9jYWJhYWM5NzA4Mzk0ODQ2ODI1MTRkYmUyMjJjMzdhNyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNWEzOTIyYTBiZjY0NDU0MmJiOGZlYWJkOTI4MWI5MzIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzg1YzRkZjM0Mjk4MzRmOWE5MjY2YTE3NjJiNjFhMWYwID0gJChgPGRpdiBpZD0iaHRtbF84NWM0ZGYzNDI5ODM0ZjlhOTI2NmExNzYyYjYxYTFmMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81YTM5MjJhMGJmNjQ0NTQyYmI4ZmVhYmQ5MjgxYjkzMi5zZXRDb250ZW50KGh0bWxfODVjNGRmMzQyOTgzNGY5YTkyNjZhMTc2MmI2MWExZjApOwogICAgICAgIAoKICAgICAgICBwb2x5Z29uXzJlYjY1YjA2NmY3ODRjNDBiMDBlOWEyYjJjNDFiZDNmLmJpbmRQb3B1cChwb3B1cF81YTM5MjJhMGJmNjQ0NTQyYmI4ZmVhYmQ5MjgxYjkzMikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGZlYXR1cmVfZ3JvdXBfN2JlZDA1Y2NmNDViNDFjNmE3NWMwZTA2NmI2MWI0N2YgPSBMLmZlYXR1cmVHcm91cCgKICAgICAgICAgICAgICAgIHt9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzY3OTQzOTcxOWY3MjQ0YzI5YWFkOWYzYTFjZjcyYWFhKTsKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl80MzMwMTQ2ZDIxNDU0YjI3ODVjZTNhMDBjNGFmN2ZiMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ4LjExNDIxNzUyMTEwODM5NCwgOS40NzA1NzM5OTQwNjk2OTZdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81NjBmMDA5NzIzMjM0YzVmOTA2NjUyM2E5OTQ1MzdiMiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNzUxZGI2M2RlNTE1NGM4N2FlZDIzYjg4NjYzZmVkZTMgPSAkKGA8ZGl2IGlkPSJodG1sXzc1MWRiNjNkZTUxNTRjODdhZWQyM2I4ODY2M2ZlZGUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81NjBmMDA5NzIzMjM0YzVmOTA2NjUyM2E5OTQ1MzdiMi5zZXRDb250ZW50KGh0bWxfNzUxZGI2M2RlNTE1NGM4N2FlZDIzYjg4NjYzZmVkZTMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzQzMzAxNDZkMjE0NTRiMjc4NWNlM2EwMGM0YWY3ZmIyLmJpbmRQb3B1cChwb3B1cF81NjBmMDA5NzIzMjM0YzVmOTA2NjUyM2E5OTQ1MzdiMikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmJhNjRkZmM5ZmZkNDUyZGFhZWFiZjMwODNmMjZjM2EgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC41ODA4MDMwODM0NDEyOTYsIDkuMzMwNzI4MTMyMDkyMTUxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83YmVkMDVjY2Y0NWI0MWM2YTc1YzBlMDY2YjYxYjQ3Zik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOGU4NzU3YTcyMWNhNGZhN2EyZjhhYmQ4YjkwNWZkMTggPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzhlN2YxYjg3MGNhNjQ4ZWRiZDdkMDhlMjA4NjhmYmYxID0gJChgPGRpdiBpZD0iaHRtbF84ZTdmMWI4NzBjYTY0OGVkYmQ3ZDA4ZTIwODY4ZmJmMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOGU4NzU3YTcyMWNhNGZhN2EyZjhhYmQ4YjkwNWZkMTguc2V0Q29udGVudChodG1sXzhlN2YxYjg3MGNhNjQ4ZWRiZDdkMDhlMjA4NjhmYmYxKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9iYmE2NGRmYzlmZmQ0NTJkYWFlYWJmMzA4M2YyNmMzYS5iaW5kUG9wdXAocG9wdXBfOGU4NzU3YTcyMWNhNGZhN2EyZjhhYmQ4YjkwNWZkMTgpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzBhZDU5MzBmNmNkMDQwOGRhY2MwOGIzMGFkMGVlZDc4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguNTE5NDkyMTg1OTU4MjQsIDkuNTg0MTYwNTUwMjM1NTQ3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83YmVkMDVjY2Y0NWI0MWM2YTc1YzBlMDY2YjYxYjQ3Zik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjlkZDBjNjM2Y2FhNDZmZWE0M2IyMTIzZGIyZDk3OGIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2RiY2I4N2EzNTE5YTRiOGZiMjdlMDFkZmIyODFmNjQxID0gJChgPGRpdiBpZD0iaHRtbF9kYmNiODdhMzUxOWE0YjhmYjI3ZTAxZGZiMjgxZjY0MSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjlkZDBjNjM2Y2FhNDZmZWE0M2IyMTIzZGIyZDk3OGIuc2V0Q29udGVudChodG1sX2RiY2I4N2EzNTE5YTRiOGZiMjdlMDFkZmIyODFmNjQxKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8wYWQ1OTMwZjZjZDA0MDhkYWNjMDhiMzBhZDBlZWQ3OC5iaW5kUG9wdXAocG9wdXBfNjlkZDBjNjM2Y2FhNDZmZWE0M2IyMTIzZGIyZDk3OGIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NhY2JjOGZiOGY0NzQ2YjVhMGMxZDJmN2NlYzllMWNlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguMTQ5MzE2NjM5MjUxNCwgOS44NzM4ODg4Nzk3OTAxOTddLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85MzUxMjA0ODJlOGY0NzljYTA3ZTE1YjNkMDIzMGI2ZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNzQ4NzhiZWVhYmE1NDMxNTg3ODc1YWU0NDYxYjE4YjEgPSAkKGA8ZGl2IGlkPSJodG1sXzc0ODc4YmVlYWJhNTQzMTU4Nzg3NWFlNDQ2MWIxOGIxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85MzUxMjA0ODJlOGY0NzljYTA3ZTE1YjNkMDIzMGI2ZS5zZXRDb250ZW50KGh0bWxfNzQ4NzhiZWVhYmE1NDMxNTg3ODc1YWU0NDYxYjE4YjEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2NhY2JjOGZiOGY0NzQ2YjVhMGMxZDJmN2NlYzllMWNlLmJpbmRQb3B1cChwb3B1cF85MzUxMjA0ODJlOGY0NzljYTA3ZTE1YjNkMDIzMGI2ZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWVkNDY0ZGU1ZDBjNDg4YmE0ODVmMTFjY2EyZGM2MGQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC40MTI5NDI3MjQ3NTU5NywgOS40OTk3ODYxNTA0NDcwOTNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF84ZDlkOGM5MGQzMGY0ZWQ0OWY5ODNkNjM2MDg5ZjcwZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZTQ2ZGE2YmNkN2M1NDAzOTgyODQ0YTNhMjY5MmI1NTMgPSAkKGA8ZGl2IGlkPSJodG1sX2U0NmRhNmJjZDdjNTQwMzk4Mjg0NGEzYTI2OTJiNTUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84ZDlkOGM5MGQzMGY0ZWQ0OWY5ODNkNjM2MDg5ZjcwZS5zZXRDb250ZW50KGh0bWxfZTQ2ZGE2YmNkN2M1NDAzOTgyODQ0YTNhMjY5MmI1NTMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2VlZDQ2NGRlNWQwYzQ4OGJhNDg1ZjExY2NhMmRjNjBkLmJpbmRQb3B1cChwb3B1cF84ZDlkOGM5MGQzMGY0ZWQ0OWY5ODNkNjM2MDg5ZjcwZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmVlOGM3ODA2YTViNGMyMmIyMWE5OGFmNmQ4ZDY0MjkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC44MjUxMjc3NDA0NDczOSwgOS4xOTEyNTQ4MTE2NDMzNDVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85NjJiZGIzNjgwNjk0YThjODBlODQwYzdiYjdhYzMwMSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMTNmMTE2ODA3N2I4NDk3MWI3MTdhZTY0NjE5NGQzZDUgPSAkKGA8ZGl2IGlkPSJodG1sXzEzZjExNjgwNzdiODQ5NzFiNzE3YWU2NDYxOTRkM2Q1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85NjJiZGIzNjgwNjk0YThjODBlODQwYzdiYjdhYzMwMS5zZXRDb250ZW50KGh0bWxfMTNmMTE2ODA3N2I4NDk3MWI3MTdhZTY0NjE5NGQzZDUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2JlZThjNzgwNmE1YjRjMjJiMjFhOThhZjZkOGQ2NDI5LmJpbmRQb3B1cChwb3B1cF85NjJiZGIzNjgwNjk0YThjODBlODQwYzdiYjdhYzMwMSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOTFmOTM4NzdkNDc1NDQ1MjhjMGRkYzc4ZTk3MGFkNGQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC4yNTY2ODEzNDk4Mjg0MiwgOS40NjI1NzcwMzYwOTk1MjVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82NGZiNWE4MzBmYjc0MDlmOGU2NzRiNWEzODJkZTg3MyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfN2Y4Y2VlODUyYjg3NDE3MmIzMzFmMmU4ZGJmNzA4MTkgPSAkKGA8ZGl2IGlkPSJodG1sXzdmOGNlZTg1MmI4NzQxNzJiMzMxZjJlOGRiZjcwODE5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF82NGZiNWE4MzBmYjc0MDlmOGU2NzRiNWEzODJkZTg3My5zZXRDb250ZW50KGh0bWxfN2Y4Y2VlODUyYjg3NDE3MmIzMzFmMmU4ZGJmNzA4MTkpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzkxZjkzODc3ZDQ3NTQ0NTI4YzBkZGM3OGU5NzBhZDRkLmJpbmRQb3B1cChwb3B1cF82NGZiNWE4MzBmYjc0MDlmOGU2NzRiNWEzODJkZTg3MykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjgyNzhiOWIxZjQxNDg3NTkxZDdiZTkxMmM2MDc5ZTcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OC42Mjc4Mjg5NzI0NTU2NDYsIDkuMjA1MjY2OTYzNTcwNjEyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83YmVkMDVjY2Y0NWI0MWM2YTc1YzBlMDY2YjYxYjQ3Zik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTVhMGE4MjA2OTk0NDY2NWExODY2M2VmYzFjMDgwZTAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2Y1YzE1NzViN2JhMjQ4ZDViNzkzMjJmODVmNWM3ZmJiID0gJChgPGRpdiBpZD0iaHRtbF9mNWMxNTc1YjdiYTI0OGQ1Yjc5MzIyZjg1ZjVjN2ZiYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTVhMGE4MjA2OTk0NDY2NWExODY2M2VmYzFjMDgwZTAuc2V0Q29udGVudChodG1sX2Y1YzE1NzViN2JhMjQ4ZDViNzkzMjJmODVmNWM3ZmJiKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yODI3OGI5YjFmNDE0ODc1OTFkN2JlOTEyYzYwNzllNy5iaW5kUG9wdXAocG9wdXBfOTVhMGE4MjA2OTk0NDY2NWExODY2M2VmYzFjMDgwZTApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzNjZmQzZWYwZDVhYjRjZjBhYzk0ZGY5YWRjYzk5YTRkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguMjg5MDQxODg1OTUwMzgsIDkuOTY4NzI5MDgyNTg2ODE0XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJyb3lhbGJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicm95YWxibHVlIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83YmVkMDVjY2Y0NWI0MWM2YTc1YzBlMDY2YjYxYjQ3Zik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjk3ZGZiYTk3ZDFkNGUxZWEwMThhNTYwMGZkYWYzZmIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzE1YjYzMTEyODEzNjQwMjU5OGYzZTIwNTA0NDc1YjdmID0gJChgPGRpdiBpZD0iaHRtbF8xNWI2MzExMjgxMzY0MDI1OThmM2UyMDUwNDQ3NWI3ZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgY29udmV4IGh1bGw8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjk3ZGZiYTk3ZDFkNGUxZWEwMThhNTYwMGZkYWYzZmIuc2V0Q29udGVudChodG1sXzE1YjYzMTEyODEzNjQwMjU5OGYzZTIwNTA0NDc1YjdmKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zY2ZkM2VmMGQ1YWI0Y2YwYWM5NGRmOWFkY2M5OWE0ZC5iaW5kUG9wdXAocG9wdXBfNjk3ZGZiYTk3ZDFkNGUxZWEwMThhNTYwMGZkYWYzZmIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzZiZTAwZjJmMTZiZTQ3MmE4M2FlOGU1MmUzZGQzOTkyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDguOTM3NTM1NjgzMDQ0MzMsIDkuNTQ0NTY2Njc0NTIwMzRdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogInJveWFsYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJyb3lhbGJsdWUiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9iNjE5ZmFlNTExNzA0OTY4YjhmODczMjhiMWM1NmIyNiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZTkxM2RjMWE3MjYyNDA0YTliM2Q5ZWRmYjg5NDkyMjYgPSAkKGA8ZGl2IGlkPSJodG1sX2U5MTNkYzFhNzI2MjQwNGE5YjNkOWVkZmI4OTQ5MjI2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBjb252ZXggaHVsbDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9iNjE5ZmFlNTExNzA0OTY4YjhmODczMjhiMWM1NmIyNi5zZXRDb250ZW50KGh0bWxfZTkxM2RjMWE3MjYyNDA0YTliM2Q5ZWRmYjg5NDkyMjYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzZiZTAwZjJmMTZiZTQ3MmE4M2FlOGU1MmUzZGQzOTkyLmJpbmRQb3B1cChwb3B1cF9iNjE5ZmFlNTExNzA0OTY4YjhmODczMjhiMWM1NmIyNikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGZlYXR1cmVfZ3JvdXBfZDFhYTRhNWI5OWEwNDk0MWI3MWZiNzg0MGU1ODNiYTkgPSBMLmZlYXR1cmVHcm91cCgKICAgICAgICAgICAgICAgIHt9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzY3OTQzOTcxOWY3MjQ0YzI5YWFkOWYzYTFjZjcyYWFhKTsKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9seWdvbl80MGEzMjY1NGJjNTY0ZGJlODNlNDdlY2EyNGUzYWZjYSA9IEwucG9seWdvbigKICAgICAgICAgICAgICAgIFtbNDkuMTc2NTI5NzYxODU3NzQsIDguOTIyOTQ5NjU2MzcwMThdLCBbNDkuODE5OTE2MzQ4MjcxNTEsIDguOTIyOTQ5NjU2MzcwMThdLCBbNDkuODE5OTE2MzQ4MjcxNTEsIDguMDYwNjIxNzUyNDkyMzJdLCBbNDkuMTc2NTI5NzYxODU3NzQsIDguMDYwNjIxNzUyNDkyMzJdXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJpbmRpYW5yZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAicmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm5vQ2xpcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEuMCwgInNtb290aEZhY3RvciI6IDEuMCwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiA1fQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfZDFhYTRhNWI5OWEwNDk0MWI3MWZiNzg0MGU1ODNiYTkpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzk4MzQzNjY0MGI1ZTRmOTZhNDc4ZjNiZTYyYWM3YmJiID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9hYjg5YmEwMmM1MWI0YmEwYjUxY2EzNWJiOTQ5NTU1NiA9ICQoYDxkaXYgaWQ9Imh0bWxfYWI4OWJhMDJjNTFiNGJhMGI1MWNhMzViYjk0OTU1NTYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTgzNDM2NjQwYjVlNGY5NmE0NzhmM2JlNjJhYzdiYmIuc2V0Q29udGVudChodG1sX2FiODliYTAyYzUxYjRiYTBiNTFjYTM1YmI5NDk1NTU2KTsKICAgICAgICAKCiAgICAgICAgcG9seWdvbl80MGEzMjY1NGJjNTY0ZGJlODNlNDdlY2EyNGUzYWZjYS5iaW5kUG9wdXAocG9wdXBfOTgzNDM2NjQwYjVlNGY5NmE0NzhmM2JlNjJhYzdiYmIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwXzdlNDdlYWQzODVjOTQ0YWQ4ZDY3ZjcxZDY0NTRiMjgyID0gTC5mZWF0dXJlR3JvdXAoCiAgICAgICAgICAgICAgICB7fQogICAgICAgICAgICApLmFkZFRvKG1hcF82Nzk0Mzk3MTlmNzI0NGMyOWFhZDlmM2ExY2Y3MmFhYSk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNWIzNjQzZTBkZmVlNGE0ZTk1MTFiZGNhOGJjMzMyYTEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS4xNzY1Mjk3NjE4NTc3NCwgOC4wOTkwMDYyOTExNzYzNDVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfN2U0N2VhZDM4NWM5NDRhZDhkNjdmNzFkNjQ1NGIyODIpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2U3NTcxNzk5OWQ5MDRkMzk4NTc5NWY1ZTAwMjQyNmQzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80Yzc0MWNmY2M2Yjk0NzM2YjZhZjZmMWEyNTcwZDc5MSA9ICQoYDxkaXYgaWQ9Imh0bWxfNGM3NDFjZmNjNmI5NDczNmI2YWY2ZjFhMjU3MGQ3OTEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2U3NTcxNzk5OWQ5MDRkMzk4NTc5NWY1ZTAwMjQyNmQzLnNldENvbnRlbnQoaHRtbF80Yzc0MWNmY2M2Yjk0NzM2YjZhZjZmMWEyNTcwZDc5MSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNWIzNjQzZTBkZmVlNGE0ZTk1MTFiZGNhOGJjMzMyYTEuYmluZFBvcHVwKHBvcHVwX2U3NTcxNzk5OWQ5MDRkMzk4NTc5NWY1ZTAwMjQyNmQzKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kNjc3NDAyOWZkZmQ0ODFjODJiYWU0ZDNhNmFiYzMwNSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5LjMxMTc1MjcyNDQ4MjEsIDguOTE0MDMwNzA3ODQ5NDcyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdlNDdlYWQzODVjOTQ0YWQ4ZDY3ZjcxZDY0NTRiMjgyKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kZDUwM2FkMmU5MWY0ODFmYjQ0MDNjNTgzYWNkMzkxZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYzM3MjI2ZTllMjE3NDRkMjg3MzBiMjAzZDZhMTgyZmQgPSAkKGA8ZGl2IGlkPSJodG1sX2MzNzIyNmU5ZTIxNzQ0ZDI4NzMwYjIwM2Q2YTE4MmZkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kZDUwM2FkMmU5MWY0ODFmYjQ0MDNjNTgzYWNkMzkxZS5zZXRDb250ZW50KGh0bWxfYzM3MjI2ZTllMjE3NDRkMjg3MzBiMjAzZDZhMTgyZmQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2Q2Nzc0MDI5ZmRmZDQ4MWM4MmJhZTRkM2E2YWJjMzA1LmJpbmRQb3B1cChwb3B1cF9kZDUwM2FkMmU5MWY0ODFmYjQ0MDNjNTgzYWNkMzkxZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjEzYTYxMjg4NmVhNDk1ZWJhYzQ3NDU5NmZjYjRiZTAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS44MDE4Mjc0MjQwMDM3MSwgOC43MDE2NzE0MDM3MzM2Nl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83ZTQ3ZWFkMzg1Yzk0NGFkOGQ2N2Y3MWQ2NDU0YjI4Mik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfY2M5Njk5NDFmY2VjNDdhZGI0YWZmMmYwMTFkNzBiMDMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzFiYWMwMzczNTA5YjQ3Yjc4MGNmNGEzNDE1NDE2MDFkID0gJChgPGRpdiBpZD0iaHRtbF8xYmFjMDM3MzUwOWI0N2I3ODBjZjRhMzQxNTQxNjAxZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfY2M5Njk5NDFmY2VjNDdhZGI0YWZmMmYwMTFkNzBiMDMuc2V0Q29udGVudChodG1sXzFiYWMwMzczNTA5YjQ3Yjc4MGNmNGEzNDE1NDE2MDFkKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9iMTNhNjEyODg2ZWE0OTVlYmFjNDc0NTk2ZmNiNGJlMC5iaW5kUG9wdXAocG9wdXBfY2M5Njk5NDFmY2VjNDdhZGI0YWZmMmYwMTFkNzBiMDMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2FiNjNiMDhkYTliNjRkMGJhNTE4YzM3NjY2ZGJjNGU2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuNTUzOTkzMTY4NTk1MTUsIDguODYzOTIyNjExMTc0MzE1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdlNDdlYWQzODVjOTQ0YWQ4ZDY3ZjcxZDY0NTRiMjgyKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yYTlhMTk2ZDE0ZDY0YzQ0OGQxNzJmY2M4M2U2ZWE3NSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNWEzMGUyZTFlZTAxNDY5M2E1OGIxMWNhYmMxNmJhNjUgPSAkKGA8ZGl2IGlkPSJodG1sXzVhMzBlMmUxZWUwMTQ2OTNhNThiMTFjYWJjMTZiYTY1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yYTlhMTk2ZDE0ZDY0YzQ0OGQxNzJmY2M4M2U2ZWE3NS5zZXRDb250ZW50KGh0bWxfNWEzMGUyZTFlZTAxNDY5M2E1OGIxMWNhYmMxNmJhNjUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2FiNjNiMDhkYTliNjRkMGJhNTE4YzM3NjY2ZGJjNGU2LmJpbmRQb3B1cChwb3B1cF8yYTlhMTk2ZDE0ZDY0YzQ0OGQxNzJmY2M4M2U2ZWE3NSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzkwYzYzYmM3YmRjNDFkZDg3MjgzODNlODg5MzAxMTMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS44MTk5MTYzNDgyNzE1MSwgOC45MjI5NDk2NTYzNzAxOF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83ZTQ3ZWFkMzg1Yzk0NGFkOGQ2N2Y3MWQ2NDU0YjI4Mik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYjM1MTI3NjZjMzNhNGFiY2EyYzhmNjk5ZmRiMzViMGIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzFlYjRlMTI0Y2RiYzQyOTY5MWZlMTRiM2VkM2U2MWYzID0gJChgPGRpdiBpZD0iaHRtbF8xZWI0ZTEyNGNkYmM0Mjk2OTFmZTE0YjNlZDNlNjFmMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYjM1MTI3NjZjMzNhNGFiY2EyYzhmNjk5ZmRiMzViMGIuc2V0Q29udGVudChodG1sXzFlYjRlMTI0Y2RiYzQyOTY5MWZlMTRiM2VkM2U2MWYzKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl83OTBjNjNiYzdiZGM0MWRkODcyODM4M2U4ODkzMDExMy5iaW5kUG9wdXAocG9wdXBfYjM1MTI3NjZjMzNhNGFiY2EyYzhmNjk5ZmRiMzViMGIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzg0ZWEzYzQwZjRmOTQ4ODI4OGIzMWVjYzY0NWM0M2RkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuNTM3ODU4MzU3NjcyNSwgOC42OTE3MjUxMDc2NTI0NTRdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfN2U0N2VhZDM4NWM5NDRhZDhkNjdmNzFkNjQ1NGIyODIpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzAyMDI1YTlmN2RlMjQ2ODdhN2MxMWZhMDhiYTE4MDBkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8xNWRlM2VkMTEzNzE0NGU3OTkzMmM4ZDk1NTUwN2YwZSA9ICQoYDxkaXYgaWQ9Imh0bWxfMTVkZTNlZDExMzcxNDRlNzk5MzJjOGQ5NTU1MDdmMGUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzAyMDI1YTlmN2RlMjQ2ODdhN2MxMWZhMDhiYTE4MDBkLnNldENvbnRlbnQoaHRtbF8xNWRlM2VkMTEzNzE0NGU3OTkzMmM4ZDk1NTUwN2YwZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfODRlYTNjNDBmNGY5NDg4Mjg4YjMxZWNjNjQ1YzQzZGQuYmluZFBvcHVwKHBvcHVwXzAyMDI1YTlmN2RlMjQ2ODdhN2MxMWZhMDhiYTE4MDBkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83M2I2YWUwNDMxM2I0ZmRjOGRmMjQ3YzZmYzg1OTcwNSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQ5LjY4NzMxNjM0MDQzNDA2LCA4LjE0MjY2MzI1NjU4MjczNF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83ZTQ3ZWFkMzg1Yzk0NGFkOGQ2N2Y3MWQ2NDU0YjI4Mik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTI1ZTQxN2ZlM2VjNGE1NzllYjg0N2YwZWY1MzY3MzAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzAwZWM5OTBhMDc2ZTQxZTRhYWMyMmZiZDA1MGIxNmNiID0gJChgPGRpdiBpZD0iaHRtbF8wMGVjOTkwYTA3NmU0MWU0YWFjMjJmYmQwNTBiMTZjYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTI1ZTQxN2ZlM2VjNGE1NzllYjg0N2YwZWY1MzY3MzAuc2V0Q29udGVudChodG1sXzAwZWM5OTBhMDc2ZTQxZTRhYWMyMmZiZDA1MGIxNmNiKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl83M2I2YWUwNDMxM2I0ZmRjOGRmMjQ3YzZmYzg1OTcwNS5iaW5kUG9wdXAocG9wdXBfOTI1ZTQxN2ZlM2VjNGE1NzllYjg0N2YwZWY1MzY3MzApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzhhNWU1NzAyOGYzMzRjZjM5ODc3ZjEwMmNiMTY5MjMzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuNzg4MzQ4NzU4NjY5MSwgOC4wNjA2MjE3NTI0OTIzMl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiZGFya3JlZCIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICJkYXJrcmVkIiwgImZpbGxPcGFjaXR5IjogMC4yLCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8oZmVhdHVyZV9ncm91cF83ZTQ3ZWFkMzg1Yzk0NGFkOGQ2N2Y3MWQ2NDU0YjI4Mik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNWYwNjc5MTViNmVjNDc3NzhjNmU1NDRjYzJkMmI2YTIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzU4NmZkNTE5ZWNhNjQ1OWQ5ZmVjZDA0MjFmNDljZTZkID0gJChgPGRpdiBpZD0iaHRtbF81ODZmZDUxOWVjYTY0NTlkOWZlY2QwNDIxZjQ5Y2U2ZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RXhhbXBsZSBwb2ludCBmb3IgZW52ZWxvcGU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNWYwNjc5MTViNmVjNDc3NzhjNmU1NDRjYzJkMmI2YTIuc2V0Q29udGVudChodG1sXzU4NmZkNTE5ZWNhNjQ1OWQ5ZmVjZDA0MjFmNDljZTZkKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl84YTVlNTcwMjhmMzM0Y2YzOTg3N2YxMDJjYjE2OTIzMy5iaW5kUG9wdXAocG9wdXBfNWYwNjc5MTViNmVjNDc3NzhjNmU1NDRjYzJkMmI2YTIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2ExMWNmMDFkYjNiNDQyODlhNzM2YmU5MWIzMzAxZjZhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuMzgwMzIzMDExODcxOTEsIDguMjM5NzUxMzMxOTUyMDk2XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJkYXJrcmVkIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogImRhcmtyZWQiLCAiZmlsbE9wYWNpdHkiOiAwLjIsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhmZWF0dXJlX2dyb3VwXzdlNDdlYWQzODVjOTQ0YWQ4ZDY3ZjcxZDY0NTRiMjgyKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9mNmEwNTE2YWRkNjY0NzgyOGZkNWYzZjc0MDk2OGRlZiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMDE3N2I0ZGZjNDUwNGQ3ODhlZjNiZDI4YjA4MDZmNDEgPSAkKGA8ZGl2IGlkPSJodG1sXzAxNzdiNGRmYzQ1MDRkNzg4ZWYzYmQyOGIwODA2ZjQxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FeGFtcGxlIHBvaW50IGZvciBlbnZlbG9wZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9mNmEwNTE2YWRkNjY0NzgyOGZkNWYzZjc0MDk2OGRlZi5zZXRDb250ZW50KGh0bWxfMDE3N2I0ZGZjNDUwNGQ3ODhlZjNiZDI4YjA4MDZmNDEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ExMWNmMDFkYjNiNDQyODlhNzM2YmU5MWIzMzAxZjZhLmJpbmRQb3B1cChwb3B1cF9mNmEwNTE2YWRkNjY0NzgyOGZkNWYzZjc0MDk2OGRlZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZmY1OTc1MDRlN2Q1NGYxNzgyMTc3YzFjMTNhMWZmMTIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS4yMDQxNDE1MDQ1OTA0MywgOC4xOTc0MDgwMDY1NDk2MjRdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImRhcmtyZWQiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiZGFya3JlZCIsICJmaWxsT3BhY2l0eSI6IDAuMiwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKGZlYXR1cmVfZ3JvdXBfN2U0N2VhZDM4NWM5NDRhZDhkNjdmNzFkNjQ1NGIyODIpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2Q2YzQ0MzQwNzhiNDRmOGZiMTUxYjkyZjU3YzA3MDNlID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8yMDIxODQ3NDMzOWE0NWIzYWU5ZjBmNWQ5YTkzZjYyYiA9ICQoYDxkaXYgaWQ9Imh0bWxfMjAyMTg0NzQzMzlhNDViM2FlOWYwZjVkOWE5M2Y2MmIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkV4YW1wbGUgcG9pbnQgZm9yIGVudmVsb3BlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2Q2YzQ0MzQwNzhiNDRmOGZiMTUxYjkyZjU3YzA3MDNlLnNldENvbnRlbnQoaHRtbF8yMDIxODQ3NDMzOWE0NWIzYWU5ZjBmNWQ5YTkzZjYyYik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZmY1OTc1MDRlN2Q1NGYxNzgyMTc3YzFjMTNhMWZmMTIuYmluZFBvcHVwKHBvcHVwX2Q2YzQ0MzQwNzhiNDRmOGZiMTUxYjkyZjU3YzA3MDNlKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgbGF5ZXJfY29udHJvbF9mNWUyODA0ZjgyMWI0OWVjODgyMTliMjFmYjA4NzRhZSA9IHsKICAgICAgICAgICAgICAgIGJhc2VfbGF5ZXJzIDogewogICAgICAgICAgICAgICAgICAgICJvcGVuc3RyZWV0bWFwIiA6IHRpbGVfbGF5ZXJfNzFiYTFhODFlN2Y2NDVlOGIyNzkxZGViNjVjOTZlMzgsCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgb3ZlcmxheXMgOiAgewogICAgICAgICAgICAgICAgICAgICJFeGFtcGxlIGNvbnZleCBodWxsIiA6IGZlYXR1cmVfZ3JvdXBfY2FiYWFjOTcwODM5NDg0NjgyNTE0ZGJlMjIyYzM3YTcsCiAgICAgICAgICAgICAgICAgICAgIkV4YW1wbGUgcG9pbnRzIGZvciBjb252ZXggaHVsbCIgOiBmZWF0dXJlX2dyb3VwXzdiZWQwNWNjZjQ1YjQxYzZhNzVjMGUwNjZiNjFiNDdmLAogICAgICAgICAgICAgICAgICAgICJFeGFtcGxlIGVudmVsb3BlIiA6IGZlYXR1cmVfZ3JvdXBfZDFhYTRhNWI5OWEwNDk0MWI3MWZiNzg0MGU1ODNiYTksCiAgICAgICAgICAgICAgICAgICAgIkV4YW1wbGUgcG9pbnRzIGZvciBlbnZlbG9wZSIgOiBmZWF0dXJlX2dyb3VwXzdlNDdlYWQzODVjOTQ0YWQ4ZDY3ZjcxZDY0NTRiMjgyLAogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgTC5jb250cm9sLmxheWVycygKICAgICAgICAgICAgICAgIGxheWVyX2NvbnRyb2xfZjVlMjgwNGY4MjFiNDllYzg4MjE5YjIxZmIwODc0YWUuYmFzZV9sYXllcnMsCiAgICAgICAgICAgICAgICBsYXllcl9jb250cm9sX2Y1ZTI4MDRmODIxYjQ5ZWM4ODIxOWIyMWZiMDg3NGFlLm92ZXJsYXlzLAogICAgICAgICAgICAgICAgeyJhdXRvWkluZGV4IjogdHJ1ZSwgImNvbGxhcHNlZCI6IGZhbHNlLCAicG9zaXRpb24iOiAidG9wcmlnaHQifQogICAgICAgICAgICApLmFkZFRvKG1hcF82Nzk0Mzk3MTlmNzI0NGMyOWFhZDlmM2ExY2Y3MmFhYSk7CiAgICAgICAgCjwvc2NyaXB0Pg== onload=\"this.contentDocument.open();this.contentDocument.write(atob(this.getAttribute('data-html')));this.contentDocument.close();\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ],
      "text/plain": [
       "<folium.folium.Map at 0x7f9a213c07c0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Initialize map\n",
    "my_map_global = folium.Map(location=[48.2460683, 9.26764125], zoom_start=7)\n",
    "\n",
    "# Create a convex hull polygon that contains some points\n",
    "list_of_points = randome_points(\n",
    "    amount=10, LON_min=48, LON_max=49, LAT_min=9, LAT_max=10\n",
    ")\n",
    "\n",
    "create_convexhull_polygon(\n",
    "    my_map_global,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example convex hull\",\n",
    "    line_color=\"lightblue\",\n",
    "    fill_color=\"lightskyblue\",\n",
    "    weight=5,\n",
    "    text=\"Example convex hull\",\n",
    ")\n",
    "\n",
    "draw_points(\n",
    "    my_map_global,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example points for convex hull\",\n",
    "    line_color=\"royalblue\",\n",
    "    fill_color=\"royalblue\",\n",
    "    text=\"Example point for convex hull\",\n",
    ")\n",
    "\n",
    "# Create an envelope polygon that contains some points\n",
    "list_of_points = randome_points(\n",
    "    amount=10, LON_min=49.1, LON_max=50, LAT_min=8, LAT_max=9\n",
    ")\n",
    "\n",
    "create_envelope_polygon(\n",
    "    my_map_global,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example envelope\",\n",
    "    line_color=\"indianred\",\n",
    "    fill_color=\"red\",\n",
    "    weight=5,\n",
    "    text=\"Example envelope\",\n",
    ")\n",
    "\n",
    "draw_points(\n",
    "    my_map_global,\n",
    "    list_of_points,\n",
    "    layer_name=\"Example points for envelope\",\n",
    "    line_color=\"darkred\",\n",
    "    fill_color=\"darkred\",\n",
    "    text=\"Example point for envelope\",\n",
    ")\n",
    "\n",
    "# Add layer control and show map\n",
    "folium.LayerControl(collapsed=False).add_to(my_map_global)\n",
    "my_map_global"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sources:\n",
    "\n",
    "* http://blog.yhat.com/posts/interactive-geospatial-analysis.html, accessed 28.12.2018\n",
    "\n",
    "* https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.spatial.ConvexHull.html, accessed 29.12.2018\n",
    "\n",
    "* https://www.oreilly.com/ideas/an-elegant-solution-to-the-convex-hull-problem, accessed 29.12.2018\n",
    "\n",
    "* https://medium.com/@vworri/simple-geospacial-mapping-with-geopandas-and-the-usual-suspects-77f46d40e807, accessed 29.12.2018\n",
    "\n",
    "* https://towardsdatascience.com/the-concave-hull-c649795c0f0f, accessed 29.12.2018\n",
    "\n",
    "* http://blog.thehumangeo.com/2014/05/12/drawing-boundaries-in-python/, accessed 04.01.2019\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
